home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / emacs_src_18_58.lha / emacs-18.58 / etc / emacstool.c < prev    next >
C/C++ Source or Header  |  1992-02-21  |  14KB  |  458 lines

  1. /*
  2.  * 
  3.  *    Copyright (C) 1986, 1988 Free Software Foundation, Inc.
  4.  
  5. This file is part of GNU Emacs.
  6.  
  7. GNU Emacs is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 1, or (at your option)
  10. any later version.
  11.  
  12. GNU Emacs is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU Emacs; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21.  * 
  22.  *
  23.  * For Emacs in SunView/Sun-Windows: (supported by Sun Unix v3.2)
  24.  * Insert a notifier filter-function to convert all useful input 
  25.  * to "key" sequences that emacs can understand.  See: Emacstool(1).
  26.  *
  27.  * Author: Jeff Peck, Sun Microsystems, Inc. <peck@sun.com>
  28.  *
  29.  * Original Idea: Ian Batten
  30.  * Updated 15-Mar-88, Jeff Peck: set IN_EMACSTOOL, TERM, TERMCAP
  31.  * Updated 10-Sep-88, Jeff Peck: add XVIEW and JLE support
  32.  * 
  33.  */
  34.  
  35. #ifdef XVIEW
  36. #include <xview/xview.h>
  37. #include <xview/panel.h>
  38. #include <xview/attr.h>
  39. #include <xview/tty.h>
  40. #include <xview/ttysw.h>        /* private defines */
  41. #include <xview/font.h>            /* for testing */
  42. #else
  43. #include <suntool/sunview.h>
  44. #include <suntool/tty.h>
  45. #include <suntool/ttysw.h>
  46. #endif XVIEW
  47.  
  48. #ifdef JLE
  49. # include <locale.h>
  50. #endif JLE
  51.  
  52. #include <stdio.h>
  53. #include <sys/file.h>
  54.  
  55. #define BUFFER_SIZE 128               /* Size of all the buffers */
  56.  
  57. /* define WANT_CAPS_LOCK to make f-key T1 (aka F1) behave as CapsLock */
  58. #define WANT_CAPS_LOCK
  59. #ifdef WANT_CAPS_LOCK
  60. int caps_lock;        /* toggle indicater for f-key T1 caps lock */
  61. static char *Caps = "[CAPS] ";        /* Caps Lock prefix string */
  62. #define CAPS_LEN 7            /* strlen (Caps) */
  63. #endif
  64.  
  65. static char *mouse_prefix = "\030\000";    /* C-x C-@ */
  66. static int   m_prefix_length = 2;       /* mouse_prefix length */
  67.  
  68. static char *key_prefix = "\030*";      /* C-x *   */
  69. static int   k_prefix_length = 2;       /* key_prefix length */
  70.  
  71. #ifdef JLE
  72. static char *emacs_name = "nemacs";    /* default run command */
  73. static char *title = "NEmacstool - ";    /* initial title */
  74. #else
  75. static char *emacs_name = "emacs";    /* default run command */
  76. static char *title = "Emacstool - ";    /* initial title */
  77. #endif JLE
  78.  
  79. static char buffer[BUFFER_SIZE];    /* send to ttysw_input */
  80. static char *bold_name = 0;         /* for -bold option */
  81.  
  82. Frame frame;                            /* Base frame for system */
  83. Tty tty_win;                /* Where emacs is reading */
  84. #ifdef XVIEW
  85. Xv_Window tty_view;            /* Where the events are in Xview*/
  86. #else
  87. Tty tty_view;                /* Place filler */
  88. #endif XVIEW
  89.  
  90. int font_width, font_height;            /* For translating pixels to chars */
  91.  
  92. int console_fd = 0;        /* for debugging: setenv DEBUGEMACSTOOL */
  93. FILE *console;            /* for debugging: setenv DEBUGEMACSTOOL */
  94.  
  95. Icon frame_icon;
  96. /* make an icon_image for the default frame_icon */
  97. static short default_image[258] = 
  98. {
  99. #include <images/terminal.icon>
  100. };
  101. mpr_static(icon_image, 64, 64, 1, default_image);
  102.  
  103. /*
  104.  * Assign a value to a set of keys
  105.  */
  106. int
  107. button_value (event)
  108.      Event *event;
  109. {
  110.   int retval = 0;
  111.   /*
  112.    * Code up the current situation:
  113.    *
  114.    * 1 = MS_LEFT;
  115.    * 2 = MS_MIDDLE;
  116.    * 4 = MS_RIGHT;
  117.    * 8 = SHIFT;
  118.    * 16 = CONTROL;
  119.    * 32 = META;
  120.    * 64 = DOUBLE;
  121.    * 128 = UP;
  122.    */
  123.  
  124.   if (MS_LEFT   == (event_id (event))) retval = 1;
  125.   if (MS_MIDDLE == (event_id (event))) retval = 2;
  126.   if (MS_RIGHT  == (event_id (event))) retval = 4;
  127.  
  128.   if (event_shift_is_down (event)) retval += 8;
  129.   if (event_ctrl_is_down  (event)) retval += 16;
  130.   if (event_meta_is_down  (event)) retval += 32;
  131.   if (event_is_up         (event)) retval += 128;
  132.   return retval;
  133. }
  134.  
  135. /*
  136.  *  Variables to store the time of the previous mouse event that was
  137.  *  sent to emacs.
  138.  *
  139.  *  The theory is that to time double clicks while ignoreing UP buttons,
  140.  *  we must keep track of the accumulated time.
  141.  *
  142.  *  If someone writes a SUN-SET-INPUT-MASK for emacstool,
  143.  *  That could be used to selectively disable UP events, 
  144.  *  and then this cruft wouldn't be necessary.
  145.  */
  146. static long prev_event_sec = 0;
  147. static long prev_event_usec = 0;
  148.  
  149. /*
  150.  *  Give the time difference in milliseconds, where one second
  151.  *  is considered infinite.
  152.  */
  153. int
  154. time_delta (now_sec, now_usec, prev_sec, prev_usec)
  155.      long now_sec, now_usec, prev_sec, prev_usec;
  156. {
  157.   long sec_delta = now_sec - prev_sec;
  158.   long usec_delta = now_usec - prev_usec;
  159.   
  160.   if (usec_delta < 0) {        /* "borrow" a second */
  161.     usec_delta += 1000000;
  162.     --sec_delta;
  163.   }
  164.   
  165.   if (sec_delta >= 10) 
  166.     return (9999);        /* Infinity */
  167.   else
  168.     return ((sec_delta * 1000) + (usec_delta / 1000));
  169. }
  170.  
  171.  
  172. /*
  173.  * Filter function to translate selected input events for emacs
  174.  * Mouse button events become ^X^@(button x-col y-line time-delta) .
  175.  * Function keys: ESC-*{c}{lrt} l,r,t for Left, Right, Top; 
  176.  * {c} encodes the keynumber as a character [a-o]
  177.  */
  178. static Notify_value
  179. input_event_filter_function (window, event, arg, type)
  180. #ifdef XVIEW
  181.      Xv_Window window;
  182. #else
  183.      Window window;
  184. #endif XVIEW
  185.      Event *event;
  186.      Notify_arg arg;
  187.      Notify_event_type type;
  188. {
  189.   struct timeval time_stamp;
  190.  
  191.   if (console_fd) fprintf(console, "Event: %d\n", event_id(event));
  192.  
  193.   /* UP L1 is the STOP key */
  194.   if (event_id(event) == WIN_STOP) {
  195.     ttysw_input(tty_win, "\007\007\007\007\007\007\007", 7);
  196.     return NOTIFY_IGNORED;
  197.   }
  198.  
  199.   /* UP L5 & L7 is Expose & Open, let them pass to sunview */
  200.   if (event_id(event) == KEY_LEFT(5) || event_id(event) == KEY_LEFT(7))
  201.     if(event_is_up (event)) 
  202.       return notify_next_event_func (window, event, arg, type);
  203.     else return NOTIFY_IGNORED;
  204.  
  205.   if (event_is_button (event)) {           /* do Mouse Button events */
  206. /* Commented out so that we send mouse up events too.
  207.    if (event_is_up (event)) 
  208.       return notify_next_event_func (window, event, arg, type);
  209. */
  210.     time_stamp = event_time (event);
  211.     ttysw_input (tty_win, mouse_prefix, m_prefix_length);
  212.     sprintf (buffer, "(%d %d %d %d)\015", 
  213.          button_value (event),
  214.          event_x (event) / font_width,
  215.          event_y (event) / font_height,
  216.          time_delta (time_stamp.tv_sec, time_stamp.tv_usec,
  217.              prev_event_sec, prev_event_usec)
  218.          );
  219.     ttysw_input (tty_win, buffer, strlen(buffer));
  220.     prev_event_sec = time_stamp.tv_sec;
  221.     prev_event_usec = time_stamp.tv_usec;
  222.     return NOTIFY_IGNORED;
  223.   }
  224.   
  225.   { /* Do the function key events */
  226.     int d;
  227.     char c = (char) 0;
  228.     if ((event_is_key_left  (event)) ?
  229.     ((d = event_id(event) - KEY_LEFT(1)   + 'a'), c='l') : 
  230.     ((event_is_key_right (event)) ?
  231.      ((d = event_id(event) - KEY_RIGHT(1) + 'a'), c='r') : 
  232.      ((event_is_key_top   (event)) ?
  233.       ((d = event_id(event) - KEY_TOP(1)  + 'a'), c='t') : 0)))
  234.       {
  235.     if (event_is_up(event)) return NOTIFY_IGNORED;
  236.     if (event_shift_is_down (event)) c = c -  32;
  237.     /* this will give a non-{lrt} for unshifted keys */
  238.     if (event_ctrl_is_down  (event)) c = c -  64;
  239.     if (event_meta_is_down  (event)) c = c + 128;
  240. #ifdef WANT_CAPS_LOCK
  241. /* set a toggle and relabel window so T1 can act like caps-lock */
  242.     if (event_id(event) == KEY_TOP(1)) 
  243.       {
  244.         /* make a frame label with and without CAPS */
  245.         strcpy (buffer, Caps); 
  246.         title = &buffer[CAPS_LEN];
  247.         strncpy (title, (char *)window_get (frame, FRAME_LABEL),
  248.              BUFFER_SIZE - CAPS_LEN);
  249.         buffer[BUFFER_SIZE] = (char) 0;    
  250.         if (strncmp (title, Caps, CAPS_LEN) == 0)
  251.           title += CAPS_LEN;          /* already Caps */
  252.         caps_lock =  (caps_lock ? 0 : CAPS_LEN);
  253.         window_set(frame, FRAME_LABEL, (title -= caps_lock), 0);
  254.         return NOTIFY_IGNORED;
  255.       }
  256. #endif
  257.     ttysw_input (tty_win, key_prefix, k_prefix_length);
  258.     sprintf (buffer, "%c%c", d, c);
  259.     ttysw_input(tty_win, buffer, strlen(buffer));
  260.  
  261.     return NOTIFY_IGNORED;
  262.       }
  263.   }
  264.   if ((event_is_ascii(event) || event_is_meta(event)) 
  265.       && event_is_up(event)) return NOTIFY_IGNORED;
  266.   /* Allow arbitary mapping of ASCII keys,
  267.      mostly, this will allow swapping BS and DEL (the -bs option) */
  268.   if (event_is_ascii(event))
  269.     event_set_id(event, event_id(event));
  270. #ifdef WANT_CAPS_LOCK
  271. /* shift alpha chars to upper case if toggle is set */
  272.   if ((caps_lock) && event_is_ascii(event)
  273.       && (event_id(event) >= 'a') && (event_id(event) <= 'z'))
  274.     event_set_id(event, (event_id(event) - 32));
  275. /* crufty, but it works for now. is there an UPCASE(event)? */
  276. #endif
  277.   return notify_next_event_func (window, event, arg, type);
  278. }
  279.  
  280. main (argc, argv)
  281.      int argc;
  282.      char **argv;
  283. {
  284.   int error_code;    /* Error codes */
  285.   
  286. #ifdef JLE
  287.   setlocale(LC_ALL, "");
  288. #endif JLE
  289.  
  290.   if(getenv("DEBUGEMACSTOOL"))
  291.     console = fdopen (console_fd = open("/dev/console",O_WRONLY), "w");
  292.  
  293.   putenv("IN_EMACSTOOL=t");    /* notify subprocess that it is in emacstool */
  294.  
  295.   if (putenv("TERM=sun") != 0)    /* TTY_WIN will be a TERM=sun window */
  296.     {fprintf (stderr, "%s: Could not set TERM=sun, using `%s'\n",
  297.          argv[0], (char *)getenv("TERM")) ;};
  298.   /*
  299.    * If TERMCAP starts with a slash, it is the pathname of the
  300.    * termcap file, not an entry extracted from it, so KEEP it!
  301.    * Otherwise, it may not relate to the new TERM, so Nuke-It.
  302.    * If there is no TERMCAP environment variable, don't make one.
  303.    */
  304.   {
  305.     char *termcap ;    /* Current TERMCAP value */
  306.     termcap = (char *)getenv("TERMCAP") ;
  307.     if (termcap && (*termcap != '/'))
  308.       {
  309.     if (putenv("TERMCAP=") != 0)
  310.       {fprintf (stderr, "%s: Could not clear TERMCAP\n", argv[0]) ;} ;
  311.       } ;
  312.   } ;
  313.   
  314.   /* find command to run as subprocess in window */
  315.   if (!(argv[0] = (char *)getenv("EMACSTOOL")))    /*  Set emacs command name */
  316.       argv[0] = emacs_name;            
  317.   /* Emacstool recognizes two special args: -rc <file> and -bs */
  318.   /* and also -bold <bold-name> */
  319.   for (argc = 1; argv[argc]; argc++)        /* Use last one on line */
  320.     {
  321.       if(!(strcmp ("-rc", argv[argc])))        /* Override if -rc given */
  322.     {int i = argc;
  323.      argv[argc--]=0;        /* kill the -rc argument */
  324.      if (argv[i+1]) {    /* move to argv[0] and squeeze the rest */
  325.        argv[0]=argv[i+1];
  326.        for (; argv[i+2]; (argv[i]=argv[i+2],argv[++i]=0));
  327.      }
  328.        }
  329.  
  330.       if (!(strcmp ("-bold", argv[argc]))) 
  331.       {int i = argc;
  332.        argv[argc--]=0;        /* kill the -bold argument */
  333.        if (argv[i+1]) {    /* move to bold_name and squeeze the rest */
  334.            bold_name = argv[i+1];
  335.            for (; argv[i+2]; (argv[i]=argv[i+2],argv[++i]=0));
  336.        }
  337.        }
  338.   };
  339.  
  340.   strcpy (buffer, title);
  341.   strncat (buffer, argv[0],         /* append run command name */
  342.        (BUFFER_SIZE - (strlen (buffer)) - (strlen (argv[0]))) - 1);
  343.  
  344.   error_code = interpose_on_window(argc,argv);
  345.   if (error_code != 0) {        /* Barf */
  346.       fprintf (stderr, "notify_interpose_event_func returns %d.\n", error_code);
  347.       exit (1);
  348.   }
  349.  
  350. #ifdef XVIEW
  351.   xv_main_loop (frame);                  /* And away we go */
  352. #else
  353.   window_main_loop (frame);
  354. #endif XVIEW
  355. }
  356.  
  357. #ifdef XVIEW
  358. int interpose_on_window(argc,argv)
  359.     int argc;
  360.     char **argv;
  361. {
  362.  
  363.     /* initialize Xview, and strip window args */
  364.     xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, 0);
  365.  
  366.     /* do this first, so arglist can override it */
  367.     frame_icon = icon_create (ICON_LABEL, "Emacstool",
  368.                   ICON_IMAGE, &icon_image,
  369.                   0);
  370.  
  371.     /* Build a frame to run in */
  372.     frame = xv_create ((Xv_Window)NULL, FRAME,
  373.                FRAME_LABEL, buffer,
  374.                FRAME_ICON, frame_icon,
  375.                0);
  376.  
  377.     /* Create a tty with emacs in it */
  378.     tty_win = xv_create (frame, TTY, WIN_IS_CLIENT_PANE,
  379.              TTY_QUIT_ON_CHILD_DEATH, TRUE, 
  380.              TTY_BOLDSTYLE, TTYSW_BOLD_INVERT,
  381.              TTY_ARGV, argv, 
  382.              0);
  383.  
  384.     if (bold_name) {
  385.     (void)xv_set(tty_win, TTY_BOLDSTYLE_NAME, bold_name, 0);
  386.     }
  387.  
  388.     font_height = (int)xv_get (tty_win, WIN_ROW_HEIGHT);
  389.     font_width  = (int)xv_get (tty_win, WIN_COLUMN_WIDTH);
  390.     font_width -= 1;        /* Xview font bug */
  391.     if (console_fd) fprintf(console, "Width = %d\n", font_width);
  392.  
  393.     tty_view = (Xv_Window) xv_get (tty_win, OPENWIN_NTH_VIEW, 0);
  394.     xv_set(tty_view,
  395.        WIN_CONSUME_EVENTS, 
  396.        WIN_MOUSE_BUTTONS, WIN_UP_EVENTS,
  397.        ACTION_ADJUST, ACTION_MENU,
  398.        WIN_ASCII_EVENTS, 
  399.        WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS,
  400.        0,
  401.        0);
  402.     /* Interpose my event function */
  403.     return (int) notify_interpose_event_func 
  404.     (tty_view, input_event_filter_function, NOTIFY_SAFE);
  405. }
  406. #else
  407. int interpose_on_window (argc, argv)
  408.  int argc;
  409.  char **argv;
  410. {
  411.     /* do this first, so arglist can override it */
  412.     frame_icon = icon_create (ICON_LABEL, "Emacstool",
  413.                   ICON_IMAGE, &icon_image,
  414.                   0);
  415.  
  416.     /* Build a frame to run in */
  417.     frame = window_create ((Window)NULL, FRAME,
  418.                FRAME_LABEL, buffer,
  419.                FRAME_ICON, frame_icon,
  420.                FRAME_ARGC_PTR_ARGV, &argc, argv,
  421.                0);
  422.  
  423.     /* Create a tty with emacs in it */
  424.     tty_win = window_create (frame, TTY, 
  425.                  TTY_QUIT_ON_CHILD_DEATH, TRUE, 
  426.                  TTY_BOLDSTYLE, TTYSW_BOLD_INVERT,
  427.                  TTY_ARGV, argv, 
  428.                  0);
  429.  
  430.     if (bold_name) {
  431.     (void)window_set(tty_win, TTY_BOLDSTYLE_NAME, bold_name, 0);
  432.     }
  433.  
  434.     /* ttysw uses pf_default, one must set WIN_FONT explicitly */
  435.                        window_set (tty_win, WIN_FONT, pf_default(), 0);
  436.     font_height = (int)window_get (tty_win, WIN_ROW_HEIGHT);
  437.     font_width  = (int)window_get (tty_win, WIN_COLUMN_WIDTH);
  438.  
  439.     tty_view = tty_win;
  440.     window_set(tty_view,
  441.            WIN_CONSUME_PICK_EVENTS, 
  442.            WIN_STOP,
  443.            WIN_MOUSE_BUTTONS, WIN_UP_EVENTS,
  444.            /* LOC_WINENTER, LOC_WINEXIT, LOC_MOVE, */
  445.            0,
  446.            WIN_CONSUME_KBD_EVENTS, 
  447.            WIN_STOP,
  448.            WIN_ASCII_EVENTS, 
  449.            WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS,
  450.            /* WIN_UP_ASCII_EVENTS, */
  451.            0,
  452.            0);
  453.     /* Interpose my event function */
  454.     return (int) notify_interpose_event_func 
  455.     (tty_view, input_event_filter_function, NOTIFY_SAFE);
  456. }
  457. #endif XVIEW
  458.